﻿using System.Windows;
using System.Windows.Input;

namespace BrasilFramework.Controle.WPF.Comum.Validacao
{

    /// <summary>
    /// Realiza filtros para mascarar a entrada de dados.
    /// </summary>
    /// <remarks>Manish Dalal</remarks>
    /// <seealso cref="http://weblogs.asp.net/manishdalal"/>
    public class TextBoxFilterService
    {

        public enum TipoFiltro
        {
            Nenhum,
            InteiroPositivo,
            Inteiro,
            ValorPositivo,
            Valor,
            Texto,
            Hora,
            Data,
            Email
        }

        private const Key PasteKeys = Key.RightCtrl | Key.LeftCtrl | Key.V;

        /// <summary>
        /// Filter Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty FilterProperty =
            DependencyProperty.RegisterAttached("Filter", typeof(TipoFiltro), typeof(TextBoxFilterService),
                                                new PropertyMetadata(OnFilterChanged));

        /// <summary>
        /// Gets the Filter property. 
        /// </summary>
        public static TipoFiltro GetFilter(DependencyObject d)
        {
            return (TipoFiltro)d.GetValue(FilterProperty);
        }

        /// <summary>
        /// Sets the Filter property.  
        /// </summary>
        public static void SetFilter(DependencyObject d, TipoFiltro value)
        {
            d.SetValue(FilterProperty, value);
        }


        /// <summary>
        /// Handles changes to the Filter property.
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            System.Windows.Controls.TextBox textBox = (TextBox)d;

            textBox.KeyDown -= textBox_KeyDown;

            if (TipoFiltro.Nenhum != (TipoFiltro)e.NewValue)
                textBox.KeyDown += textBox_KeyDown;
        }

        /// <summary>
        /// Handles the KeyDown event of the textBox control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> instance containing the event data.</param>
        private static void textBox_KeyDown(object sender, KeyEventArgs e)
        {
            // bypass other keys!
            if (IsValidOtherKey(e.Key)) return;

            TipoFiltro filterType = GetFilter((DependencyObject)sender);
            System.Windows.Controls.TextBox textBox = sender as System.Windows.Controls.TextBox ??
                                                      e.OriginalSource as System.Windows.Controls.TextBox;
            //
            switch (filterType)
            {
                case TipoFiltro.InteiroPositivo:
                    e.Handled = !IsValidIntegerKey(textBox, e.Key, (int)e.Key, false);
                    break;
                case TipoFiltro.Inteiro:
                    e.Handled = !IsValidIntegerKey(textBox, e.Key, (int)e.Key, true);
                    break;
                case TipoFiltro.ValorPositivo:
                    e.Handled = !IsValidDecmialKey(textBox, e.Key, (int)e.Key, false);
                    break;
                case TipoFiltro.Valor:
                    e.Handled = !IsValidDecmialKey(textBox, e.Key, (int)e.Key, true);
                    break;
                case TipoFiltro.Texto:
                    e.Handled = !IsValidAlphaKey(e.Key);
                    break;
                case TipoFiltro.Data:
                    e.Handled = !IsValidAlphaKey(e.Key);
                    break;
                case TipoFiltro.Hora:
                    if (textBox != null)
                        if (textBox.Text.Length == 2)
                            e.Handled = !(Keyboard.Modifiers == ModifierKeys.Shift && e.Key == Key.Oem2);
                        else
                            e.Handled = !IsValidIntegerKey(textBox, e.Key, (int)e.Key, false);
                    break;
            }
        }

        /// <summary>
        /// Determines whether the specified key is valid other key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>
        /// 	<c>true</c> if [is valid other key] [the specified key]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsValidOtherKey(Key key)
        {
            // allow control keys
            System.Diagnostics.Debug.WriteLine(key.ToString());
            if ((Keyboard.Modifiers & ModifierKeys.Control) != 0) return true;

            // allow
            // Back, Tab, Enter, Shift, Ctrl, Alt, CapsLock, Escape, PageUp, PageDown
            // End, Home, Left, Up, Right, Down, Insert, Delete 
            // except for space!
            // allow all Fx keys
            return (key < Key.D0 && key != Key.Space)
                   || (key > Key.Z && key < Key.NumPad0)
                   || (Key.F1 <= key && key <= Key.F24);
            // we need to examine all others!
        }

        /// <summary>
        /// Determines whether the specified key is valid integer key for the specified text box.
        /// </summary>
        /// <param name="textBox">The text box.</param>
        /// <param name="key">The key.</param>
        /// <param name="platformKeyCode">The platform key code.</param>
        /// <param name="negativeAllowed">if set to <c>true</c> [negative allowed].</param>
        /// <returns>
        /// 	<c>true</c> if the specified key is valid integer key for the specified text box; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsValidIntegerKey(System.Windows.Controls.TextBox textBox, Key key, int platformKeyCode, bool negativeAllowed)
        {
            if ((Keyboard.Modifiers & ModifierKeys.Shift) != 0) return false;
            if (Key.D0 <= key && key <= Key.D9) return true;
            if (Key.NumPad0 <= key && key <= Key.NumPad9) return true;
            if (negativeAllowed && (key == Key.Subtract || key == Key.OemMinus || (key == Key.None && platformKeyCode == 189)))
                return 0 == textBox.Text.Length;

            return false;
        }

        /// <summary>
        /// Determines whether the specified key is valid decmial key for the specified text box.
        /// </summary>
        /// <param name="textBox">The text box.</param>
        /// <param name="key">The key.</param>
        /// <param name="platformKeyCode">The platform key code.</param>
        /// <param name="negativeAllowed">if set to <c>true</c> [negative allowed].</param>
        /// <returns>
        /// 	<c>true</c> if the specified key is valid decmial key for the specified text box; otherwise, <c>false</c>.
        /// </returns>
        private static bool IsValidDecmialKey(System.Windows.Controls.TextBox textBox, Key key, int platformKeyCode, bool negativeAllowed)
        {
            if (key == Key.OemComma || key == Key.Decimal || (key == Key.None && platformKeyCode == 190))
                return !(textBox.Text.Contains(".") || textBox.Text.Contains(","));

            return IsValidIntegerKey(textBox, key, platformKeyCode, negativeAllowed);
        }

        /// <summary>
        /// Determines whether the specified key is valid alpha key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>
        /// 	<c>true</c> if the specified key is valid alpha key for the specified text box.; otherwise, <c>false</c>.
        /// </returns>
        private static bool IsValidAlphaKey(Key key)
        {
            return Key.A <= key && key <= Key.Z;
        }
    }
}